package com.bytefy.server.db;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sleepycat.je.Cursor;
import com.sleepycat.je.CursorConfig;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.Transaction;

public class Persistence {
	private static final String CHARSET = "utf-8";
	private static Environment env;
	private static Database db;
	private static Logger log = LoggerFactory.getLogger(Persistence.class);
	private static String path = "./";
	private static String name = "data";
	private static String id;

	static {
		new File(path).mkdir();
		log.info("Starting persistence");
		EnvironmentConfig envConfig = new EnvironmentConfig();
		envConfig.setCachePercent(90);
		envConfig.setTxnNoSync(true);
		envConfig.setAllowCreate(true);
		env = new Environment(new File(path), envConfig);
		DatabaseConfig dbConfig = new DatabaseConfig();
		dbConfig.setDeferredWrite(true);
		dbConfig.setAllowCreate(true);
		db = env.openDatabase(null, name, dbConfig);
		log.info("Started persistence");

		final Persistence db = new Persistence();
		id = db.get("__id__");
		if (id == null) {
			id = UUID.randomUUID().toString();
			db.put("__id__", id);
			log.info("First start, generate id = " + id);
			db.sync();
		}
		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				db.close();
			}
		});
	}

	private static boolean stoped;

	public void put(Object key, Object value, Transaction tx) {
		db.put(tx, toEntry(key.toString()), toEntry(value.toString()));
	}

	public void put(Object key, Object value) {
		this.put(key, value, null);
	}

	public String get(String key) {
		DatabaseEntry valueEntry = new DatabaseEntry();
		OperationStatus status = db.get(null, toEntry(key), valueEntry,
				LockMode.READ_COMMITTED);
		if (!OperationStatus.SUCCESS.equals(status))
			return null;
		return toString(valueEntry);
	}

	public void close() {
		log.info("Close persistence");
		try {
			stoped = true;
			db.close();
			env.close();
		} catch (Throwable t) {
			t.printStackTrace();
		}
	}

	public void sync() {
		log.info("Sync started");
		db.sync();
		log.info("Sync finished");
	}

	private DatabaseEntry toEntry(String d) {
		DatabaseEntry e = null;
		try {
			e = new DatabaseEntry(d.getBytes(CHARSET));
		} catch (UnsupportedEncodingException ex) {
			ex.printStackTrace();
		}
		return e;
	}

	private String toString(DatabaseEntry e) {
		String s = null;
		try {
			s = new String(e.getData(), CHARSET);
		} catch (UnsupportedEncodingException ex) {
			ex.printStackTrace();
		}
		return s;
	}

	public static void normalize() {
		Cursor cursor = db.openCursor(null, null);
		DatabaseEntry foundKey = new DatabaseEntry();
		DatabaseEntry foundData = new DatabaseEntry();

		while (cursor.getNext(foundKey, foundData, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
			try {
				String keyString = new String(foundKey.getData(), "UTF-8");
				String dataString = new String(foundData.getData(), "UTF-8");
				System.out.println("Key | Data : " + keyString + " | "
						+ dataString + "");
			} catch (Throwable t) {
				t.printStackTrace();
			}
		}
		cursor.close();
	}
}

class ArrayEntry {
	public String prev;
	public String next;
	public String value;

	@Override
	public String toString() {
		StringBuilder b = new StringBuilder();
		b.append(prev);
		b.append("_");
		b.append(next);
		b.append("_");
		b.append(value);
		return b.toString();
	}
}